package com.shuorikeji.huohuo.utils;

import android.content.Context;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;

public class FontDownloader {
    private static final String FONT_CACHE_DIR = "book_fonts";

    public interface FontDownloadCallback {
        void onSuccess(File fontFile);
        void onProgress(int progress);
        void onFailure(String error);
    }

    public static void downloadFont(Context context, String fontUrl, FontDownloadCallback callback) {
        OkHttpClient client = new OkHttpClient.Builder()
                .addNetworkInterceptor(chain -> {
                    Response originalResponse = chain.proceed(chain.request());
                    return originalResponse.newBuilder()
                            .body(new ProgressResponseBody(originalResponse.body(), callback))
                            .build();
                })
                .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(),SSLSocketClient.IGNORE_SSL_TRUST_MANAGER_X509)
                .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
                .build();

        Request request = new Request.Builder().url(fontUrl).build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callback.onFailure(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (!response.isSuccessful()) {
                    callback.onFailure("下载失败: " + response.code());
                    return;
                }

                File cacheDir = new File(context.getExternalFilesDir(null), FONT_CACHE_DIR);
                if (!cacheDir.exists()) cacheDir.mkdirs();

                String fontName = getFontNameFromUrl(fontUrl);
                File fontFile = new File(cacheDir, fontName);

                try (InputStream input = response.body().byteStream();
                     OutputStream output = new FileOutputStream(fontFile)) {
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = input.read(buffer)) != -1) {
                        output.write(buffer, 0, bytesRead);
                    }
                    callback.onSuccess(fontFile);
                } catch (IOException e) {
                    callback.onFailure(e.getMessage());
                }
            }
        });
    }

    private static String getFontNameFromUrl(String url) {
        return url.substring(url.lastIndexOf('/') + 1);
    }

    static class ProgressResponseBody extends ResponseBody {
        private final ResponseBody responseBody;
        private final FontDownloadCallback callback;
        private BufferedSource bufferedSource;

        ProgressResponseBody(ResponseBody responseBody, FontDownloadCallback callback) {
            this.responseBody = responseBody;
            this.callback = callback;
        }

        @Override public MediaType contentType() {
            return responseBody.contentType();
        }

        @Override public long contentLength() {
            return responseBody.contentLength();
        }

        @Override public BufferedSource source() {
            if (bufferedSource == null) {
                bufferedSource = Okio.buffer(source(responseBody.source()));
            }
            return bufferedSource;
        }

        private Source source(Source source) {
            return new ForwardingSource(source) {
                long totalBytesRead = 0L;
                long contentLength = 0L;

                @Override public long read(Buffer sink, long byteCount) throws IOException {
                    if (contentLength == 0) {
                        contentLength = contentLength();
                    }
                    long bytesRead = super.read(sink, byteCount);
                    totalBytesRead += bytesRead != -1 ? bytesRead : 0;
                    int progress = (int) ((100 * totalBytesRead) / contentLength);
                    callback.onProgress(progress);
                    return bytesRead;
                }
            };
        }
    }
}
